using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace LiteNetLib.Utils
{
	public class NetPacketProcessor
	{
		protected delegate void SubscribeDelegate(NetDataReader reader, object userData);

		[CompilerGenerated]
		private sealed class _003C_003Ec__DisplayClass26_0<T> where T : class, new()
		{
			public Func<T> packetConstructor;

			public NetPacketProcessor _003C_003E4__this;

			public Action<T> onReceive;

			internal void _003CSubscribe_003Eb__0(NetDataReader reader, object userData)
			{
				T val = packetConstructor();
				_003C_003E4__this._netSerializer.Deserialize(reader, val);
				onReceive(val);
			}
		}

		[CompilerGenerated]
		private sealed class _003C_003Ec__DisplayClass27_0<T, TUserData> where T : class, new()
		{
			public Func<T> packetConstructor;

			public NetPacketProcessor _003C_003E4__this;

			public Action<T, TUserData> onReceive;

			internal void _003CSubscribe_003Eb__0(NetDataReader reader, object userData)
			{
				T val = packetConstructor();
				_003C_003E4__this._netSerializer.Deserialize(reader, val);
				onReceive(val, (TUserData)userData);
			}
		}

		[CompilerGenerated]
		private sealed class _003C_003Ec__DisplayClass28_0<T> where T : class, new()
		{
			public NetPacketProcessor _003C_003E4__this;

			public T reference;

			public Action<T> onReceive;

			internal void _003CSubscribeReusable_003Eb__0(NetDataReader reader, object userData)
			{
				_003C_003E4__this._netSerializer.Deserialize(reader, reference);
				onReceive(reference);
			}
		}

		[CompilerGenerated]
		private sealed class _003C_003Ec__DisplayClass29_0<T, TUserData> where T : class, new()
		{
			public NetPacketProcessor _003C_003E4__this;

			public T reference;

			public Action<T, TUserData> onReceive;

			internal void _003CSubscribeReusable_003Eb__0(NetDataReader reader, object userData)
			{
				_003C_003E4__this._netSerializer.Deserialize(reader, reference);
				onReceive(reference, (TUserData)userData);
			}
		}

		[CompilerGenerated]
		private sealed class _003C_003Ec__DisplayClass30_0<T, TUserData> where T : INetSerializable
		{
			public Func<T> packetConstructor;

			public Action<T, TUserData> onReceive;

			internal void _003CSubscribeNetSerializable_003Eb__0(NetDataReader reader, object userData)
			{
				T arg = packetConstructor();
				arg.Deserialize(reader);
				onReceive(arg, (TUserData)userData);
			}
		}

		[CompilerGenerated]
		private sealed class _003C_003Ec__DisplayClass31_0<T> where T : INetSerializable
		{
			public Func<T> packetConstructor;

			public Action<T> onReceive;

			internal void _003CSubscribeNetSerializable_003Eb__0(NetDataReader reader, object userData)
			{
				T obj = packetConstructor();
				obj.Deserialize(reader);
				onReceive(obj);
			}
		}

		[CompilerGenerated]
		private sealed class _003C_003Ec__DisplayClass32_0<T, TUserData> where T : INetSerializable, new()
		{
			public T reference;

			public Action<T, TUserData> onReceive;

			internal void _003CSubscribeNetSerializable_003Eb__0(NetDataReader reader, object userData)
			{
				reference.Deserialize(reader);
				onReceive(reference, (TUserData)userData);
			}
		}

		[CompilerGenerated]
		private sealed class _003C_003Ec__DisplayClass33_0<T> where T : INetSerializable, new()
		{
			public T reference;

			public Action<T> onReceive;

			internal void _003CSubscribeNetSerializable_003Eb__0(NetDataReader reader, object userData)
			{
				reference.Deserialize(reader);
				onReceive(reference);
			}
		}

		private readonly Dictionary<string, ulong> _hashCache = new Dictionary<string, ulong>();

		private readonly char[] _hashBuffer = new char[1024];

		private readonly NetSerializer _netSerializer;

		private readonly Dictionary<ulong, SubscribeDelegate> _callbacks = new Dictionary<ulong, SubscribeDelegate>();

		private readonly NetDataWriter _netDataWriter = new NetDataWriter();

		public NetPacketProcessor()
		{
			_netSerializer = new NetSerializer();
		}

		public NetPacketProcessor(int maxStringLength)
		{
			_netSerializer = new NetSerializer(maxStringLength);
		}

		protected virtual ulong GetHash(Type type)
		{
			string fullName = type.FullName;
			ulong value;
			if (_hashCache.TryGetValue(fullName, out value))
			{
				return value;
			}
			value = 14695981039346656037uL;
			fullName.CopyTo(0, _hashBuffer, 0, fullName.Length);
			for (int i = 0; i < fullName.Length; i++)
			{
				value ^= _hashBuffer[i];
				value *= 1099511628211L;
			}
			_hashCache.Add(fullName, value);
			return value;
		}

		protected virtual SubscribeDelegate GetCallbackFromData(NetDataReader reader)
		{
			ulong uLong = reader.GetULong();
			SubscribeDelegate value;
			if (!_callbacks.TryGetValue(uLong, out value))
			{
				throw new ParseException("Undefined packet in NetDataReader");
			}
			return value;
		}

		protected virtual void WriteHash(Type type, NetDataWriter writer)
		{
			writer.Put(GetHash(type));
		}

		public bool RegisterNestedType<T>() where T : struct, INetSerializable
		{
			return _netSerializer.RegisterNestedType<T>();
		}

		public bool RegisterNestedType<T>(Action<NetDataWriter, T> writeDelegate, Func<NetDataReader, T> readDelegate)
		{
			return _netSerializer.RegisterNestedType(writeDelegate, readDelegate);
		}

		public bool RegisterNestedType<T>(Func<T> constructor) where T : class, INetSerializable
		{
			return _netSerializer.RegisterNestedType(constructor);
		}

		public void ReadAllPackets(NetDataReader reader)
		{
			while (reader.AvailableBytes > 0)
			{
				ReadPacket(reader);
			}
		}

		public void ReadAllPackets(NetDataReader reader, object userData)
		{
			while (reader.AvailableBytes > 0)
			{
				ReadPacket(reader, userData);
			}
		}

		public void ReadPacket(NetDataReader reader)
		{
			ReadPacket(reader, null);
		}

		public void Send<T>(NetPeer peer, T packet, DeliveryMethod options) where T : class, new()
		{
			_netDataWriter.Reset();
			Write(_netDataWriter, packet);
			peer.Send(_netDataWriter, options);
		}

		public void SendNetSerializable<T>(NetPeer peer, T packet, DeliveryMethod options) where T : INetSerializable
		{
			_netDataWriter.Reset();
			WriteNetSerializable(_netDataWriter, packet);
			peer.Send(_netDataWriter, options);
		}

		public void Send<T>(NetManager manager, T packet, DeliveryMethod options) where T : class, new()
		{
			_netDataWriter.Reset();
			Write(_netDataWriter, packet);
			manager.SendToAll(_netDataWriter, options);
		}

		public void SendNetSerializable<T>(NetManager manager, T packet, DeliveryMethod options) where T : INetSerializable
		{
			_netDataWriter.Reset();
			WriteNetSerializable(_netDataWriter, packet);
			manager.SendToAll(_netDataWriter, options);
		}

		public void Write<T>(NetDataWriter writer, T packet) where T : class, new()
		{
			WriteHash(typeof(T), writer);
			_netSerializer.Serialize(writer, packet);
		}

		public void WriteNetSerializable<T>(NetDataWriter writer, T packet) where T : INetSerializable
		{
			WriteHash(typeof(T), writer);
			packet.Serialize(writer);
		}

		public byte[] Write<T>(T packet) where T : class, new()
		{
			_netDataWriter.Reset();
			WriteHash(typeof(T), _netDataWriter);
			_netSerializer.Serialize(_netDataWriter, packet);
			return _netDataWriter.CopyData();
		}

		public byte[] WriteNetSerializable<T>(T packet) where T : INetSerializable
		{
			_netDataWriter.Reset();
			WriteHash(typeof(T), _netDataWriter);
			packet.Serialize(_netDataWriter);
			return _netDataWriter.CopyData();
		}

		public void ReadPacket(NetDataReader reader, object userData)
		{
			GetCallbackFromData(reader)(reader, userData);
		}

		public void Subscribe<T>(Action<T> onReceive, Func<T> packetConstructor) where T : class, new()
		{
			_003C_003Ec__DisplayClass26_0<T> _003C_003Ec__DisplayClass26_ = new _003C_003Ec__DisplayClass26_0<T>();
			_003C_003Ec__DisplayClass26_.packetConstructor = packetConstructor;
			_003C_003Ec__DisplayClass26_._003C_003E4__this = this;
			_003C_003Ec__DisplayClass26_.onReceive = onReceive;
			_netSerializer.Register<T>();
			_callbacks[GetHash(typeof(T))] = new SubscribeDelegate(_003C_003Ec__DisplayClass26_._003CSubscribe_003Eb__0);
		}

		public void Subscribe<T, TUserData>(Action<T, TUserData> onReceive, Func<T> packetConstructor) where T : class, new()
		{
			_003C_003Ec__DisplayClass27_0<T, TUserData> _003C_003Ec__DisplayClass27_ = new _003C_003Ec__DisplayClass27_0<T, TUserData>();
			_003C_003Ec__DisplayClass27_.packetConstructor = packetConstructor;
			_003C_003Ec__DisplayClass27_._003C_003E4__this = this;
			_003C_003Ec__DisplayClass27_.onReceive = onReceive;
			_netSerializer.Register<T>();
			_callbacks[GetHash(typeof(T))] = new SubscribeDelegate(_003C_003Ec__DisplayClass27_._003CSubscribe_003Eb__0);
		}

		public void SubscribeReusable<T>(Action<T> onReceive) where T : class, new()
		{
			_003C_003Ec__DisplayClass28_0<T> _003C_003Ec__DisplayClass28_ = new _003C_003Ec__DisplayClass28_0<T>();
			_003C_003Ec__DisplayClass28_._003C_003E4__this = this;
			_003C_003Ec__DisplayClass28_.onReceive = onReceive;
			_netSerializer.Register<T>();
			_003C_003Ec__DisplayClass28_.reference = new T();
			_callbacks[GetHash(typeof(T))] = new SubscribeDelegate(_003C_003Ec__DisplayClass28_._003CSubscribeReusable_003Eb__0);
		}

		public void SubscribeReusable<T, TUserData>(Action<T, TUserData> onReceive) where T : class, new()
		{
			_003C_003Ec__DisplayClass29_0<T, TUserData> _003C_003Ec__DisplayClass29_ = new _003C_003Ec__DisplayClass29_0<T, TUserData>();
			_003C_003Ec__DisplayClass29_._003C_003E4__this = this;
			_003C_003Ec__DisplayClass29_.onReceive = onReceive;
			_netSerializer.Register<T>();
			_003C_003Ec__DisplayClass29_.reference = new T();
			_callbacks[GetHash(typeof(T))] = new SubscribeDelegate(_003C_003Ec__DisplayClass29_._003CSubscribeReusable_003Eb__0);
		}

		public void SubscribeNetSerializable<T, TUserData>(Action<T, TUserData> onReceive, Func<T> packetConstructor) where T : INetSerializable
		{
			_003C_003Ec__DisplayClass30_0<T, TUserData> _003C_003Ec__DisplayClass30_ = new _003C_003Ec__DisplayClass30_0<T, TUserData>();
			_003C_003Ec__DisplayClass30_.packetConstructor = packetConstructor;
			_003C_003Ec__DisplayClass30_.onReceive = onReceive;
			_callbacks[GetHash(typeof(T))] = new SubscribeDelegate(_003C_003Ec__DisplayClass30_._003CSubscribeNetSerializable_003Eb__0);
		}

		public void SubscribeNetSerializable<T>(Action<T> onReceive, Func<T> packetConstructor) where T : INetSerializable
		{
			_003C_003Ec__DisplayClass31_0<T> _003C_003Ec__DisplayClass31_ = new _003C_003Ec__DisplayClass31_0<T>();
			_003C_003Ec__DisplayClass31_.packetConstructor = packetConstructor;
			_003C_003Ec__DisplayClass31_.onReceive = onReceive;
			_callbacks[GetHash(typeof(T))] = new SubscribeDelegate(_003C_003Ec__DisplayClass31_._003CSubscribeNetSerializable_003Eb__0);
		}

		public void SubscribeNetSerializable<T, TUserData>(Action<T, TUserData> onReceive) where T : INetSerializable, new()
		{
			_003C_003Ec__DisplayClass32_0<T, TUserData> _003C_003Ec__DisplayClass32_ = new _003C_003Ec__DisplayClass32_0<T, TUserData>();
			_003C_003Ec__DisplayClass32_.onReceive = onReceive;
			_003C_003Ec__DisplayClass32_.reference = new T();
			_callbacks[GetHash(typeof(T))] = new SubscribeDelegate(_003C_003Ec__DisplayClass32_._003CSubscribeNetSerializable_003Eb__0);
		}

		public void SubscribeNetSerializable<T>(Action<T> onReceive) where T : INetSerializable, new()
		{
			_003C_003Ec__DisplayClass33_0<T> _003C_003Ec__DisplayClass33_ = new _003C_003Ec__DisplayClass33_0<T>();
			_003C_003Ec__DisplayClass33_.onReceive = onReceive;
			_003C_003Ec__DisplayClass33_.reference = new T();
			_callbacks[GetHash(typeof(T))] = new SubscribeDelegate(_003C_003Ec__DisplayClass33_._003CSubscribeNetSerializable_003Eb__0);
		}

		public bool RemoveSubscription<T>()
		{
			return _callbacks.Remove(GetHash(typeof(T)));
		}
	}
}
